package com.qmock.pay.runner;

import com.qmock.pay.anno.*;
import com.qmock.pay.common.ConfigParse;
import com.qmock.pay.exception.SignEncException;
import com.qmock.pay.http.DefaultXMLResponseParameters;
import com.qmock.pay.http.PayHttpRequest;
import com.qmock.pay.http.PayHttpResponse;
import com.qmock.pay.http.PayMockServer;

import org.apache.http.HttpException;
import org.apache.log4j.Logger;
import org.junit.runners.model.FrameworkMethod;
import org.qmock.runner.statement.Interceptor;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutionException;

/**
 * @author tianqing.wang
 */
public class PayInterceptor implements Interceptor {
    private static Logger logger = Logger.getLogger(PayInterceptor.class);
    private Mock mock;
    private Url url;
    private When when;
    private CallBack callBack;
    private ThenReturn thenReturn;
    private PayHttpRequest payHttpRequest;
    private PayMockServer payMockServer;
    private boolean isAsynRequest=false;
    public void interceptorBefore(FrameworkMethod method, Object test) {
        this.payHttpRequest=new PayHttpRequest();
        annotationParse(method,test);
    }

    public void interceptorAfter(FrameworkMethod method, Object test) {
        if(isAsynRequest=false){
            this.payHttpRequest=new PayHttpRequest();
            Map<String,String> map = new HashMap<String, String>();
            map.put("status","over");
            try {
                this.payHttpRequest.post(ConfigParse.serverUrl()+"/config").with(map).execute();
            } catch (HttpException e) {
                e.printStackTrace();
            }
            this.payHttpRequest.close();
        }

    }

    private void annotationParse(FrameworkMethod method,Object test){
        if(test.getClass().isAnnotationPresent(Mock.class)||method.getMethod().isAnnotationPresent(Mock.class)){
            logger.info("包含Mock的Bank信息---模拟银行"+getMock(method,test).value().toString());
            if(method.getMethod().isAnnotationPresent(ThenReturn.class)){
                logger.info("此Case模拟同步请求。");
                this.mock=getMock(method,test);
                this.thenReturn=method.getMethod().getAnnotation(ThenReturn.class);
                String path=this.thenReturn.value();
                Bank bank=this.mock.value();
                Map<String,String> config = new HashMap<String,String>();
                config.put("status","start");
                config.putAll(new DefaultXMLResponseParameters(path).toPairs().getPairs());
                try {
                    this.payHttpRequest.post(ConfigParse.serverUrl()+"/config").with(config).execute();
                } catch (HttpException e) {
                    e.printStackTrace();
                }
                this.payHttpRequest.close();
                this.isAsynRequest=false;
            }
        }else{
            if(method.getMethod().isAnnotationPresent(When.class)||test.getClass().isAnnotationPresent(When.class)){
                if(method.getMethod().isAnnotationPresent(CallBack.class)){
                    logger.info("此Case模拟异步请求。");
                    this.payMockServer=new PayMockServer();
                    this.mock=getMock(method,test);
                    this.callBack=method.getAnnotation(CallBack.class);
                    Bank bank = this.mock.value();
                    this.when=getWhen(method,test);
                    String callbackUrl = this.callBack.value();
                    String path = this.when.request();
                    try {
                        PayHttpResponse response=this.payMockServer.mockBank(bank).when(path).callBack(callbackUrl);
                        logger.info(response.body());
                    } catch (SignEncException e) {
                        e.printStackTrace();
                        throw new RuntimeException("异步回调请求出现了错误，请检查参数配置是否正确。");
                    }
                }
                this.isAsynRequest=true;
            }
        }
    }

    private Mock getMock(FrameworkMethod method,Object test){
        if(test.getClass().isAnnotationPresent(Mock.class)){
            return test.getClass().getAnnotation(Mock.class);
        }else if(method.getMethod().isAnnotationPresent(Mock.class)){
            return method.getMethod().getAnnotation(Mock.class);
        }else{
            logger.warn("没有获得MOCK银行的信息");
            return null;
        }
    }

    private Url getUrl(FrameworkMethod method,Object test){
        if(test.getClass().isAnnotationPresent(Url.class)){
            return test.getClass().getAnnotation(Url.class);
        }else if(method.getMethod().isAnnotationPresent(Url.class)){
            return method.getMethod().getAnnotation(Url.class);
        }else{
            logger.warn("没有获得服务器端URL的信息");
            return null;
        }
    }

    private When getWhen(FrameworkMethod method,Object test){
        if(method.getMethod().isAnnotationPresent(When.class)){
            return method.getMethod().getAnnotation(When.class);
        }else{
            return null;
        }
    }
}
